home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / gfx / misc / gnuplot-src.lha / gnuplot-3.7.1src / gnuplot-3.7.1.lha / gnuplot-3.7.1 / gplt_x11.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-15  |  50.0 KB  |  1,824 lines

  1. #ifndef lint;
  2.         /,„ÈSid = "$Id: gplt_x11.c,v 1.16.2.4 1999/10/15 16:04:50 lhecking Exp $";
  3. #endif
  4.  
  5. /* GNUPLOT - gplt_x11.c */
  6.  
  7. /*[
  8.  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted,
  12.  * provided that the above copyright notice appear in all copies and
  13.  * that both that copyright notice and this permission notice appear
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the complete modified source code.  Modifications are to
  18.  * be distributed as patches to the released version.  Permission to
  19.  * distribute binaries produced by compiling modified sources is granted,
  20.  * provided you
  21.  *   1. distribute the corresponding source modifications from the
  22.  *    released version in the form of a patch file along with the binaries,
  23.  *   2. add special version identification to distinguish your version
  24.  *    in addition to the base release version number,
  25.  *   3. provide your name and address as the primary contact for the
  26.  *    support of your modified version, and
  27.  *   4. retain our contact information in regard to use of the base
  28.  *    software.
  29.  * Permission to distribute the released version of the source code along
  30.  * with corresponding source modifications in the form of a patch file is
  31.  * granted with same provisions 2 through 4 for binary distributions.
  32.  *
  33.  * This software is provided "as is" without express or implied warranty
  34.  * to the extent permitted by applicable law.
  35. ]*/
  36.  
  37.  
  38. /* lph changes:
  39.  * (a) make EXPORT_SELECTION the default and specify NOEXPORT to undefine
  40.  * (b) append X11 terminal number to resource name
  41.  * (c) change cursor for active terminal
  42.  */
  43.  
  44. /*-----------------------------------------------------------------------------
  45.  *   gnuplot_x11 - X11 outboard terminal driver for gnuplot 3.3
  46.  *
  47.  *   Requires installation of companion inboard x11 driver in gnuplot/term.c
  48.  *
  49.  *   Acknowledgements: 
  50.  *      Chris Peterson (MIT)
  51.  *      Dana Chee (Bellcore) 
  52.  *      Arthur Smith (Cornell)
  53.  *      Hendri Hondorp (University of Twente, The Netherlands)
  54.  *      Bill Kucharski (Solbourne)
  55.  *      Charlie Kline (University of Illinois)
  56.  *      Yehavi Bourvine (Hebrew University of Jerusalem, Israel)
  57.  *      Russell Lang (Monash University, Australia)
  58.  *      O'Reilly & Associates: X Window System - Volumes 1 & 2
  59.  *
  60.  *   This code is provided as is and with no warranties of any kind.
  61.  *
  62.  * drd: change to allow multiple windows to be maintained independently
  63.  *       
  64.  * There is a mailing list for gnuplot users. Note, however, that the
  65.  * newsgroup 
  66.  *    comp.graphics.apps.gnuplot 
  67.  * is identical to the mailing list (they
  68.  * both carry the same set of messages). We prefer that you read the
  69.  * messages through that newsgroup, to subscribing to the mailing list.
  70.  * (If you can read that newsgroup, and are already on the mailing list,
  71.  * please send a message to majordomo@dartmouth.edu, asking to be
  72.  * removed from the mailing list.)
  73.  *
  74.  * The address for mailing to list members is
  75.  *       info-gnuplot@dartmouth.edu
  76.  * and for mailing administrative requests is 
  77.  *       majordomo@dartmouth.edu
  78.  * The mailing list for bug reports is 
  79.  *       bug-gnuplot@dartmouth.edu
  80.  * The list of those interested in beta-test versions is
  81.  *       info-gnuplot-beta@dartmouth.edu
  82.  *---------------------------------------------------------------------------*/
  83.  
  84. /* drd : export the graph via ICCCM primary selection. well... not quite
  85.  * ICCCM since we dont support full list of targets, but this
  86.  * is a start.  define EXPORT_SELECTION if you want this feature
  87.  */
  88.  
  89. /*lph: add a "feature" to undefine EXPORT_SELECTION
  90.    The following makes EXPORT_SELECTION the default and 
  91.    defining NOEXPORT over-rides the default
  92.  */
  93.  
  94. #ifdef HAVE_CONFIG_H
  95. # include "config.h"
  96. #endif
  97.  
  98. #ifdef EXPORT_SELECTION
  99. # undef EXPORT_SELECTION
  100. #endif /* EXPORT SELECTION */
  101. #ifndef NOEXPORT
  102. # define EXPORT_SELECTION XA_PRIMARY
  103. #endif /* NOEXPORT */
  104.  
  105.  
  106. #if !(defined(VMS) || defined(CRIPPLED_SELECT))
  107. # define DEFAULT_X11
  108. #endif
  109.  
  110. #if defined(VMS) && defined(CRIPPLED_SELECT)
  111. Error. Incompatible options.
  112. #endif
  113.  
  114.  
  115. #include <X11/Xos.h>
  116. #include <X11/Xlib.h>
  117. #include <X11/Xresource.h>
  118. #include <X11/Xutil.h>
  119. #include <X11/Xatom.h>
  120. #include <X11/keysym.h>
  121.  
  122. #include <signal.h>
  123.  
  124. #ifdef HAVE_SYS_BSDTYPES_H
  125. # include <sys/bsdtypes.h>
  126. #endif /* HAVE_SYS_BSDTYPES_H */
  127.  
  128. #ifdef __EMX__
  129. /* for gethostname ... */
  130. # include <netdb.h>
  131. #endif
  132.  
  133. #if defined(HAVE_SYS_SELECT_H) && !defined(VMS)
  134. # include <sys/select.h>
  135. #endif /* HAVE_SYS_SELECT_H && !VMS */
  136.  
  137. #ifndef FD_SET
  138. # define FD_SET(n, p)    ((p)->fds_bits[0] |= (1 << ((n) % 32)))
  139. # define FD_CLR(n, p)    ((p)->fds_bits[0] &= ~(1 << ((n) % 32)))
  140. # define FD_ISSET(n, p)  ((p)->fds_bits[0] & (1 << ((n) % 32)))
  141. # define FD_ZERO(p)      memset((char *)(p),'\0',sizeof(*(p)))
  142. #endif /* not FD_SET */
  143.  
  144. #include "plot.h"
  145.  
  146. #if defined(HAVE_SYS_SYSTEMINFO_H) && defined(HAVE_SYSINFO)
  147. # include <sys/systeminfo.h>
  148. # define SYSINFO_METHOD "sysinfo"
  149. # define GP_SYSTEMINFO(host) sysinfo (SI_HOSTNAME, (host), MAXHOSTNAMELEN)
  150. #else
  151. # define SYSINFO_METHOD "gethostname"
  152. # define GP_SYSTEMINFO(host) gethostname ((host), MAXHOSTNAMELEN)
  153. #endif /* HAVE_SYS_SYSTEMINFO_H && HAVE_SYSINFO */
  154.  
  155. #ifdef VMS
  156. # ifdef __DECC
  157. #  include <starlet.h>
  158. # endif                /* __DECC */
  159. # define EXIT(status) sys$delprc(0,0)    /* VMS does not drop itself */
  160. #else
  161. # define EXIT(status) exit(status)
  162. #endif
  163.  
  164. #ifdef OSK
  165. # define EINTR    E_ILLFNC
  166. #endif
  167.  
  168. /* information about one window/plot */
  169.  
  170. typedef struct plot_struct {
  171.     Window window;
  172.     Pixmap pixmap;
  173.     unsigned int posn_flags;
  174.     int x, y;
  175.     unsigned int width, height;    /* window size */
  176.     unsigned int px, py;    /* pointsize */
  177.     int ncommands, max_commands;
  178.     char **commands;
  179. } plot_struct;
  180.  
  181. void store_command __PROTO((char *line, plot_struct * plot));
  182. void prepare_plot __PROTO((plot_struct * plot, int term_number));
  183. void delete_plot __PROTO((plot_struct * plot));
  184.  
  185. int record __PROTO((void));
  186. void process_event __PROTO((XEvent * event));    /* from Xserver */
  187.  
  188. void mainloop __PROTO((void));
  189.  
  190. void display __PROTO((plot_struct * plot));
  191.  
  192. void reset_cursor __PROTO((void));
  193.  
  194. void preset __PROTO((int argc, char *argv[]));
  195. char *pr_GetR __PROTO((XrmDatabase db, char *resource));
  196. void pr_color __PROTO((void));
  197. void pr_dashes __PROTO((void));
  198. void pr_font __PROTO((void));
  199. void pr_geometry __PROTO((void));
  200. void pr_pointsize __PROTO((void));
  201. void pr_width __PROTO((void));
  202. Window pr_window __PROTO((unsigned int flags, int x, int y, unsigned int width, unsigned height));
  203. void pr_raise __PROTO((void));
  204. void pr_persist __PROTO((void));
  205.  
  206. #ifdef EXPORT_SELECTION
  207. void export_graph __PROTO((plot_struct * plot));
  208. void handle_selection_event __PROTO((XEvent * event));
  209. #endif
  210.  
  211. #define FallbackFont "fixed"
  212.  
  213. #define Ncolors 13
  214. unsigned long colors[Ncolors];
  215.  
  216. #define Nwidths 10
  217. unsigned int widths[Nwidths] = { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  218.  
  219. #define Ndashes 10
  220. char dashes[Ndashes][5];
  221.  
  222. #define MAX_WINDOWS 16
  223.  
  224. #define XC_crosshair 34
  225.  
  226.  
  227. struct plot_struct plot_array[MAX_WINDOWS];
  228.  
  229.  
  230. Display *dpy;
  231. int scr;
  232. Window root;
  233. Visual *vis;
  234. GC gc = (GC) 0;
  235. XFontStruct *font;
  236. int do_raise = 1, persist = 0;
  237. KeyCode q_keycode;
  238. Cursor cursor;
  239.  
  240. int windows_open = 0;
  241.  
  242. int gX = 100, gY = 100;
  243. unsigned int gW = 640, gH = 450;
  244. unsigned int gFlags = PSize;
  245.  
  246. unsigned int BorderWidth = 2;
  247. unsigned int D;            /* depth */
  248.  
  249. Bool Mono = 0, Gray = 0, Rv = 0, Clear = 0;
  250. char Name[64] = "gnuplot";
  251. char Class[64] = "Gnuplot";
  252.  
  253. int cx = 0, cy = 0, vchar;
  254. double xscale, yscale, pointsize;
  255. #define X(x) (int) ((x) * xscale)
  256. #define Y(y) (int) ((4095-(y)) * yscale)
  257.  
  258. #define Nbuf 1024
  259. char buf[Nbuf], **commands = (char **) 0;
  260. static int buffered_input_available = 0;
  261.  
  262. FILE *X11_ipc;
  263. char X11_ipcpath[32];
  264.  
  265. /* when using an ICCCM-compliant window manager, we can ask it
  266.  * to send us an event when user chooses 'close window'. We do this
  267.  * by setting WM_DELETE_WINDOW atom in property WM_PROTOCOLS
  268.  */
  269.  
  270. Atom WM_PROTOCOLS, WM_DELETE_WINDOW;
  271.  
  272. XPoint Diamond[5], Triangle[4];
  273. XSegment Plus[2], Cross[2], Star[4];
  274.  
  275. /*-----------------------------------------------------------------------------
  276.  *   main program 
  277.  *---------------------------------------------------------------------------*/
  278.  
  279. int
  280. main(argc, argv)
  281. int argc;
  282. char *argv[];
  283. {
  284.  
  285.  
  286. #ifdef OSK
  287.     /* malloc large blocks, otherwise problems with fragmented mem */
  288.     _mallocmin(102400);
  289. #endif
  290. #ifdef __EMX__
  291.     /* close open file handles */
  292.     fcloseall();
  293. #endif
  294.  
  295.     FPRINTF((stderr, "gnuplot_X11 starting up\n"));
  296.  
  297.     preset(argc, argv);
  298.  
  299. /* set up the alternative cursor */
  300.     cursor = XCreateFontCursor(dpy, XC_crosshair);
  301.  
  302.     mainloop();
  303.  
  304.     if (persist) {
  305.     FPRINTF((stderr, "waiting for %d windows\n", windows_open));
  306.     /* read x events until all windows have been quit */
  307.     while (windows_open > 0) {
  308.         XEvent event;
  309.         XNextEvent(dpy, &event);
  310.         process_event(&event);
  311.     }
  312.     }
  313.     XCloseDisplay(dpy);
  314.  
  315.     FPRINTF((stderr, "exiting\n"));
  316.  
  317.     EXIT(0);
  318. }
  319.  
  320. /*-----------------------------------------------------------------------------
  321.  *   mainloop processing - process X events and input from gnuplot
  322.  *
  323.  *   Three different versions of main loop processing are provided to support
  324.  *   three different platforms.
  325.  * 
  326.  *   DEFAULT_X11:     use select() for both X events and input on stdin 
  327.  *                    from gnuplot inboard driver
  328.  *
  329.  *   CRIPPLED_SELECT: use select() to service X events and check during 
  330.  *                    select timeout for temporary plot file created
  331.  *                    by inboard driver
  332.  *
  333.  *   VMS:             use XNextEvent to service X events and AST to
  334.  *                    service input from gnuplot inboard driver on stdin 
  335.  *---------------------------------------------------------------------------*/
  336.  
  337.  
  338. #ifdef DEFAULT_X11
  339. /*-----------------------------------------------------------------------------
  340.  *    DEFAULT_X11 mainloop
  341.  *---------------------------------------------------------------------------*/
  342.  
  343. void
  344. mainloop()
  345. {
  346.     int nf, cn = ConnectionNumber(dpy), in;
  347.     fd_set_size_t nfds;
  348.     struct timeval timeout, *timer = (struct timeval *) 0;
  349.     fd_set tset;
  350.  
  351.     X11_ipc = stdin;
  352.     in = fileno(X11_ipc);
  353.  
  354. #ifdef ISC22
  355. /* Added by Robert Eckardt, RobertE@beta.TP2.Ruhr-Uni-Bochum.de */
  356.     timeout.tv_sec = 0;        /* select() in ISC2.2 needs timeout */
  357.     timeout.tv_usec = 300000;    /* otherwise input from gnuplot is */
  358.     timer = &timeout;        /* suspended til next X event. */
  359. #endif /* ISC22   (0.3s are short enough not to be noticed */
  360.  
  361.     while (1) {
  362.  
  363.     /* XNextEvent does an XFlush() before waiting. But here.
  364.      * we must ensure that the queue is flushed, since we
  365.      * dont call XNextEvent until an event arrives. (I have
  366.      * twice wasted quite some time over this issue, so now
  367.      * I am making sure of it !
  368.      */
  369.  
  370.     XFlush(dpy);
  371.  
  372.     FD_ZERO(&tset);
  373.     FD_SET(cn, &tset);
  374.  
  375.     /* Don't wait for events if we know that input is
  376.      * already sitting in a buffer.  Also don't wait for
  377.      * input to become available.
  378.     */
  379.     if (buffered_input_available) {
  380.         timeout.tv_sec  = 0;
  381.         timeout.tv_usec = 0;
  382.         timer = &timeout;
  383.     } else {
  384.         timer = (struct timeval *) 0;
  385.         FD_SET(in, &tset);
  386.     }
  387.  
  388.     nfds = (cn > in) ? cn + 1 : in + 1;
  389.  
  390.     nf = select(nfds, SELECT_FD_SET_CAST &tset, 0, 0, timer);
  391.  
  392.     if (nf < 0) {
  393.         if (errno == EINTR)
  394.         continue;
  395.         fprintf(stderr, "gnuplot: select failed. errno:%d\n", errno);
  396.         EXIT(1);
  397.     }
  398.  
  399.     if (nf > 0)
  400.         XNoOp(dpy);
  401.  
  402.     if (FD_ISSET(cn, &tset)) {
  403.         /* used to use CheckMaskEvent() but that cannot receive
  404.          * maskable events such as ClientMessage. So now we do
  405.          * one event, then return to the select.
  406.          * And that almost works, except that under some Xservers
  407.          * running without a window manager (e.g. Hummingbird Exceed under Win95)
  408.          * a bogus ConfigureNotify is sent followed by a valid ConfigureNotify
  409.          * when the window is maximized.  The two events are queued, apparently
  410.          * in a single I/O because select() above doesn't see the second, valid
  411.          * event.  This little loop fixes the problem by flushing the
  412.          * event queue completely.
  413.          */
  414.         XEvent xe;
  415.         do {
  416.         XNextEvent(dpy, &xe);
  417.         process_event(&xe);
  418.         } while (XPending(dpy));
  419.     }
  420.  
  421.     if (FD_ISSET(in, &tset) || buffered_input_available) {
  422.         if (!record())    /* end of input */
  423.         return;
  424.     }
  425.     }
  426. }
  427.  
  428.  
  429. #elif defined(CRIPPLED_SELECT)
  430. /*-----------------------------------------------------------------------------
  431.  *    CRIPPLED_SELECT mainloop
  432.  *---------------------------------------------------------------------------*/
  433.  
  434. void
  435. mainloop()
  436. {
  437.     fd_set_size_t nf, nfds, cn = ConnectionNumber(dpy);
  438.     struct timeval timeout, *timer;
  439.     fd_set tset;
  440.     unsigned long all = (unsigned long) (-1L);
  441.     XEvent xe;
  442.  
  443.     timeout.tv_sec = 1;
  444.     timeout.tv_usec = 0;
  445.     timer = &timeout;
  446.     sprintf(X11_ipcpath, "/tmp/Gnuplot_%d", getppid());
  447.     nfds = cn + 1;
  448.  
  449.     while (1) {
  450.     XFlush(dpy);        /* see above */
  451.  
  452.     FD_ZERO(&tset);
  453.     FD_SET(cn, &tset);
  454.  
  455.     /* Don't wait for events if we know that input is
  456.      * already sitting in a buffer.  Also don't wait for
  457.      * input to become available.
  458.     */
  459.     if (buffered_input_available) {
  460.         timeout.tv_sec  = 0;
  461.         timeout.tv_usec = 0;
  462.         timer = &timeout;
  463.     } else {
  464.         timer = (struct timeval *) 0;
  465.         FD_SET(in, &tset);
  466.     }
  467.  
  468.     nfds = (cn > in) ? cn + 1 : in + 1;
  469.  
  470.     nf = select(nfds, SELECT_FD_SET_CAST &tset, 0, 0, timer);
  471.  
  472.     if (nf < 0) {
  473.         if (errno == EINTR)
  474.         continue;
  475.         fprintf(stderr, "gnuplot: select failed. errno:%d\n", errno);
  476.         EXIT(1);
  477.     }
  478.  
  479.     if (nf > 0)
  480.         XNoOp(dpy);
  481.  
  482.     if (FD_ISSET(cn, &tset)) {
  483.         while (XCheckMaskEvent(dpy, all, &xe)) {
  484.         process_event(&xe);
  485.         }
  486.     }
  487.     if ((X11_ipc = fopen(X11_ipcpath, "r"))) {
  488.         unlink(X11_ipcpath);
  489.         record();
  490.         fclose(X11_ipc);
  491.     }
  492.     }
  493. }
  494.  
  495.  
  496. #elif defined(VMS)
  497. /*-----------------------------------------------------------------------------
  498.  *    VMS mainloop - Yehavi Bourvine - YEHAVI@VMS.HUJI.AC.IL
  499.  *---------------------------------------------------------------------------*/
  500.  
  501. /*  In VMS there is no decent Select(). hence, we have to loop inside
  502.  *  XGetNextEvent for getting the next X window event. In order to get input
  503.  *  from the master we assign a channel to SYS$INPUT and use AST's in order to
  504.  *  receive data. In order to exit the mainloop, we need to somehow make
  505.  *  XNextEvent return from within the ast. We do this with a XSendEvent() to
  506.  *  ourselves !
  507.  *  This needs a window to send the message to, so we create an unmapped window
  508.  *  for this purpose. Event type XClientMessage is perfect for this, but it
  509.  *  appears that such messages come from elsewhere (motif window manager,
  510.  *  perhaps ?) So we need to check fairly carefully that it is the ast event
  511.  *  that has been received.
  512.  */
  513.  
  514. #include <iodef.h>
  515. char STDIIN[] = "SYS$INPUT:";
  516. short STDIINchannel, STDIINiosb[4];
  517. struct {
  518.     short size, type;
  519.     char *address;
  520. } STDIINdesc;
  521. char STDIINbuffer[64];
  522. int status;
  523.  
  524. ast()
  525. {
  526.     int status = sys$qio(0, STDIINchannel, IO$_READVBLK, STDIINiosb, record,
  527.              0, STDIINbuffer, sizeof(STDIINbuffer) - 1, 0, 0, 0, 0);
  528.     if ((status & 0x1) == 0)
  529.     EXIT(status);
  530. }
  531.  
  532. Window message_window;
  533.  
  534. void
  535. mainloop()
  536. {
  537.     /* dummy unmapped window for receiving internally-generated terminate
  538.      * messages
  539.      */
  540.     message_window = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 1, 0, 0);
  541.  
  542.     STDIINdesc.size = strlen(STDIIN);
  543.     STDIINdesc.type = 0;
  544.     STDIINdesc.address = STDIIN;
  545.     status = sys$assign(&STDIINdesc, &STDIINchannel, 0, 0, 0);
  546.     if ((status & 0x1) == 0)
  547.     EXIT(status);
  548.     ast();
  549.  
  550.     for (;;) {
  551.     XEvent xe;
  552.     XNextEvent(dpy, &xe);
  553.     if (xe.type == ClientMessage && xe.xclient.window == message_window) {
  554.         if (xe.xclient.message_type == None &&
  555.         xe.xclient.format == 8 &&
  556.         strcmp(xe.xclient.data.b, "die gnuplot die") == 0) {
  557.         FPRINTF((stderr, "quit message from ast\n"));
  558.         return;
  559.         } else {
  560.         FPRINTF((stderr, "Bogus XClientMessage event from window manager ?\n"));
  561.         }
  562.     }
  563.     process_event(&xe);
  564.     }
  565. }
  566. #else /* !(DEFAULT_X11 || CRIPPLED_SELECT || VMS */
  567. You lose. No mainloop.
  568. #endif                /* !(DEFAULT_X11 || CRIPPLED_SELECT || VMS */
  569.  
  570. /* delete a window / plot */
  571.  
  572. void
  573. delete_plot(plot)
  574. plot_struct *plot;
  575. {
  576.     int i;
  577.  
  578.     FPRINTF((stderr, "Delete plot %d\n", plot - plot_array));
  579.  
  580.     for (i = 0; i < plot->ncommands; ++i)
  581.     free(plot->commands[i]);
  582.     plot->ncommands = 0;
  583.  
  584.     if (plot->window) {
  585.     FPRINTF((stderr, "Destroy window 0x%x\n", plot->window));
  586.     XDestroyWindow(dpy, plot->window);
  587.     plot->window = None;
  588.     --windows_open;
  589.     }
  590.     if (plot->pixmap) {
  591.     XFreePixmap(dpy, plot->pixmap);
  592.     plot->pixmap = None;
  593.     }
  594.     /* but preserve geometry */
  595. }
  596.  
  597.  
  598. /* prepare the plot structure */
  599.  
  600. void
  601. prepare_plot(plot, term_number)
  602. plot_struct *plot;
  603. int term_number;
  604. {
  605.     int i;
  606.     char *term_name;
  607.  
  608.     for (i = 0; i < plot->ncommands; ++i)
  609.     free(plot->commands[i]);
  610.     plot->ncommands = 0;
  611.  
  612.     if (!plot->posn_flags) {
  613.     /* first time this window has been used - use default or -geometry
  614.      * settings
  615.      */
  616.     plot->posn_flags = gFlags;
  617.     plot->x = gX;
  618.     plot->y = gY;
  619.     plot->width = gW;
  620.     plot->height = gH;
  621.     }
  622.     if (!plot->window) {
  623.     plot->window = pr_window(plot->posn_flags, plot->x, plot->y, plot->width, plot->height);
  624.     ++windows_open;
  625.  
  626.     /* append the X11 terminal number (if greater than zero) */
  627.  
  628.     if (term_number) {
  629.         char new_name[60];
  630.         XFetchName(dpy, plot->window, &term_name);
  631.         FPRINTF((stderr, "Window title is %s\n", term_name));
  632.  
  633.         sprintf(new_name, "%.55s%3d", term_name, term_number);
  634.         FPRINTF((stderr, "term_number  is %d\n", term_number));
  635.  
  636.         XStoreName(dpy, plot->window, new_name);
  637.  
  638.         sprintf(new_name, "gplt%3d", term_number);
  639.         XSetIconName(dpy, plot->window, new_name);
  640.     }
  641.     }
  642. /* We don't know that it is the same window as before, so we reset the
  643.  * cursors for all windows and then define the cursor for the active
  644.  * window 
  645.  */
  646.     reset_cursor();
  647.     XDefineCursor(dpy, plot->window, cursor);
  648.  
  649. }
  650.  
  651. /* store a command in a plot structure */
  652.  
  653. void
  654. store_command(buffer, plot)
  655. char *buffer;
  656. plot_struct *plot;
  657. {
  658.     char *p;
  659.  
  660.     FPRINTF((stderr, "Store in %d : %s", plot - plot_array, buffer));
  661.  
  662.     if (plot->ncommands >= plot->max_commands) {
  663.     plot->max_commands = plot->max_commands * 2 + 1;
  664.     plot->commands = (plot->commands)
  665.         ? (char **) realloc(plot->commands, plot->max_commands * sizeof(char *))
  666.     : (char **) malloc(sizeof(char *));
  667.     }
  668.     p = (char *) malloc((unsigned) strlen(buffer) + 1);
  669.     if (!plot->commands || !p) {
  670.     fputs("gnuplot: can't get memory. X11 aborted.\n", stderr);
  671.     EXIT(1);
  672.     }
  673.     plot->commands[plot->ncommands++] = strcpy(p, buffer);
  674. }
  675.  
  676. #ifndef VMS
  677.  
  678. /* Handle input.  Use read instead of fgets because stdio buffering
  679. * causes trouble when combined with calls to select.
  680. */
  681. int
  682. read_input ()
  683. {
  684.     static int rdbuf_size = 10*Nbuf;
  685.     static char rdbuf[10*Nbuf-1];
  686.     static int total_chars;
  687.     static int rdbuf_offset;
  688.     static int buf_offset;
  689.     static int partial_read = 0;
  690.     int fd = fileno (X11_ipc);
  691.  
  692.     if (! partial_read)
  693.     buf_offset = 0;
  694.  
  695.     if (! buffered_input_available) {
  696.     total_chars = read (fd, rdbuf, rdbuf_size);
  697.     buffered_input_available = 1;
  698.     partial_read = 0;
  699.     rdbuf_offset = 0;
  700.     if (total_chars < 0)
  701.         return -1;
  702.     }
  703.  
  704.     if (rdbuf_offset < total_chars) {
  705.     while (rdbuf_offset < total_chars && buf_offset < Nbuf) {
  706.         char c = rdbuf[rdbuf_offset++];
  707.         buf[buf_offset++] = c;
  708.         if (c == '\n')
  709.         break;
  710.     }
  711.  
  712.     if (buf_offset == Nbuf) {
  713.         fputs("\
  714. \n\
  715. gnuplot: buffer overflow in read_input!\n\
  716. gnuplot: X11 aborted.\n", stderr);
  717.         EXIT(1);
  718.     } else
  719.         buf[buf_offset] = NUL;
  720.     }
  721.  
  722.     if (rdbuf_offset == total_chars) {
  723.     buffered_input_available = 0;
  724.     if (buf[buf_offset-1] != '\n')
  725.         partial_read = 1;
  726.     }
  727.  
  728.     return partial_read;
  729. }
  730.  
  731.  
  732. /*-----------------------------------------------------------------------------
  733.  *   record - record new plot from gnuplot inboard X11 driver (Unix)
  734.  *---------------------------------------------------------------------------*/
  735.  
  736. int
  737. record()
  738. {
  739.     static plot_struct *plot = plot_array;
  740.  
  741.     while (1) {
  742.     int status = read_input ();
  743.     if (status != 0)
  744.         return status;
  745.  
  746.     switch (*buf) {
  747.     case 'G':        /* enter graphics mode */
  748.         {
  749.         int plot_number = atoi(buf + 1);    /* 0 if none specified */
  750.  
  751.         if (plot_number < 0 || plot_number >= MAX_WINDOWS)
  752.             plot_number = 0;
  753.  
  754.         FPRINTF((stderr, "plot for window number %d\n", plot_number));
  755.         plot = plot_array + plot_number;
  756.         prepare_plot(plot, plot_number);
  757.         continue;
  758.         }
  759.     case 'E':        /* leave graphics mode / suspend */
  760.         display(plot);
  761.         return 1;
  762.     case 'R':        /* leave x11 mode */
  763.         reset_cursor();
  764.         return 0;
  765.     default:
  766.         store_command(buf, plot);
  767.         continue;
  768.     }
  769.     }
  770. }
  771.  
  772. #else /* VMS */
  773. /*-----------------------------------------------------------------------------
  774.  *   record - record new plot from gnuplot inboard X11 driver (VMS)
  775.  *---------------------------------------------------------------------------*/
  776.  
  777. record()
  778. {
  779.     static plot_struct *plot = plot_array;
  780.  
  781.     int status;
  782.  
  783.     if ((STDIINiosb[0] & 0x1) == 0)
  784.     EXIT(STDIINiosb[0]);
  785.     STDIINbuffer[STDIINiosb[1]] = '\0';
  786.     strcpy(buf, STDIINbuffer);
  787.  
  788.     switch (*buf) {
  789.     case 'G':            /* enter graphics mode */
  790.     {
  791.         int plot_number = atoi(buf + 1);    /* 0 if none specified */
  792.         if (plot_number < 0 || plot_number >= MAX_WINDOWS)
  793.         plot_number = 0;
  794.         FPRINTF((stderr, "plot for window number %d\n", plot_number));
  795.         plot = plot_array + plot_number;
  796.         prepare_plot(plot, plot_number);
  797.         break;
  798.     }
  799.     case 'E':            /* leave graphics mode */
  800.     display(plot);
  801.     break;
  802.     case 'R':            /* exit x11 mode */
  803.     FPRINTF((stderr, "received R - sending ClientMessage\n"));
  804.     reset_cursor();
  805.     sys$cancel(STDIINchannel);
  806.     /* this is ridiculous - cook up an event to ourselves,
  807.      * in order to get the mainloop() out of the XNextEvent() call
  808.      * it seems that window manager can also send clientmessages,
  809.      * so put a checksum into the message
  810.      */
  811.     {
  812.         XClientMessageEvent event;
  813.         event.type = ClientMessage;
  814.         event.send_event = True;
  815.         event.display = dpy;
  816.         event.window = message_window;
  817.         event.message_type = None;
  818.         event.format = 8;
  819.         strcpy(event.data.b, "die gnuplot die");
  820.         XSendEvent(dpy, message_window, False, 0, (XEvent *) & event);
  821.         XFlush(dpy);
  822.     }
  823.     return;            /* no ast */
  824.     default:
  825.     store_command(buf, plot);
  826.     break;
  827.     }
  828.     ast();
  829. }
  830. #endif /* VMS */
  831.  
  832.  
  833. /*-----------------------------------------------------------------------------
  834.  *   display - display a stored plot
  835.  *---------------------------------------------------------------------------*/
  836.  
  837. void
  838. display(plot)
  839. plot_struct *plot;
  840. {
  841.     int n, x, y, sw, sl, lt = 0, width, type, point, px, py;
  842.     int user_width = 1;        /* as specified by plot...linewidth */
  843.     char *buffer, *str;
  844.     enum JUSTIFY jmode;
  845.  
  846.     FPRINTF((stderr, "Display %d ; %d commands\n", plot - plot_array, plot->ncommands));
  847.  
  848.     if (plot->ncommands == 0)
  849.     return;
  850.  
  851.     /* set scaling factor between internal driver & window geometry */
  852.     xscale = plot->width / 4096.0;
  853.     yscale = plot->height / 4096.0;
  854.  
  855.     /* initial point sizes, until overridden with P7xxxxyyyy */
  856.     px = (int) (xscale * pointsize);
  857.     py = (int) (yscale * pointsize);
  858.  
  859.     /* create new pixmap & GC */
  860.     if (gc)
  861.     XFreeGC(dpy, gc);
  862.  
  863.     if (!plot->pixmap) {
  864.     FPRINTF((stderr, "Create pixmap %d : %dx%dx%d\n", plot - plot_array, plot->width,
  865.          plot->height, D));
  866.     plot->pixmap = XCreatePixmap(dpy, root, plot->width, plot->height, D);
  867.     }
  868.     gc = XCreateGC(dpy, plot->pixmap, 0, (XGCValues *) 0);
  869.  
  870.     XSetFont(dpy, gc, font->fid);
  871.  
  872.     /* set pixmap background */
  873.     XSetForeground(dpy, gc, colors[0]);
  874.     XFillRectangle(dpy, plot->pixmap, gc, 0, 0, plot->width, plot->height);
  875.     XSetBackground(dpy, gc, colors[0]);
  876.  
  877.     if (!plot->window) {
  878.     plot->window = pr_window(plot->posn_flags, plot->x, plot->y, plot->width, plot->height);
  879.     ++windows_open;
  880.     }
  881.     /* top the window but don't put keyboard or mouse focus into it. */
  882.     if (do_raise)
  883.     XMapRaised(dpy, plot->window);
  884.  
  885.     /* momentarily clear the window first if requested */
  886.     if (Clear) {
  887.     XClearWindow(dpy, plot->window);
  888.     XFlush(dpy);
  889.     }
  890.     /* loop over accumulated commands from inboard driver */
  891.     for (n = 0; n < plot->ncommands; n++) {
  892.     buffer = plot->commands[n];
  893.  
  894.     /*   X11_vector(x,y) - draw vector  */
  895.     if (*buffer == 'V') {
  896.         sscanf(buffer, "V%4d%4d", &x, &y);
  897.         XDrawLine(dpy, plot->pixmap, gc, X(cx), Y(cy), X(x), Y(y));
  898.         cx = x;
  899.         cy = y;
  900.     }
  901.     /*   X11_move(x,y) - move  */
  902.     else if (*buffer == 'M')
  903.         sscanf(buffer, "M%4d%4d", &cx, &cy);
  904.  
  905.     /*   X11_put_text(x,y,str) - draw text   */
  906.     else if (*buffer == 'T') {
  907.         sscanf(buffer, "T%4d%4d", &x, &y);
  908.         str = buffer + 9;
  909.         sl = strlen(str) - 1;
  910.         sw = XTextWidth(font, str, sl);
  911.  
  912.         switch (jmode) {
  913.         case LEFT:
  914.         sw = 0;
  915.         break;
  916.         case CENTRE:
  917.         sw = -sw / 2;
  918.         break;
  919.         case RIGHT:
  920.         sw = -sw;
  921.         break;
  922.         }
  923.  
  924.         XSetForeground(dpy, gc, colors[2]);
  925.         XDrawString(dpy, plot->pixmap, gc, X(x) + sw, Y(y) + vchar / 3, str, sl);
  926.         XSetForeground(dpy, gc, colors[lt + 3]);
  927.     } else if (*buffer == 'F') {    /* fill box */
  928.         int style, xtmp, ytmp, w, h;
  929.  
  930.         if (sscanf(buffer + 1, "%4d%4d%4d%4d%4d", &style, &xtmp, &ytmp, &w, &h) == 5) {
  931.         /* gnuplot has origin at bottom left, but X uses top left
  932.          * There may be an off-by-one (or more) error here.
  933.          * style ignored here for the moment
  934.          */
  935.         ytmp += h;    /* top left corner of rectangle to be filled */
  936.         w *= xscale;
  937.         h *= yscale;
  938.         XSetForeground(dpy, gc, colors[0]);
  939.         XFillRectangle(dpy, plot->pixmap, gc, X(xtmp), Y(ytmp), w, h);
  940.         XSetForeground(dpy, gc, colors[lt + 3]);
  941.         }
  942.     }
  943.     /*   X11_justify_text(mode) - set text justification mode  */
  944.     else if (*buffer == 'J')
  945.         sscanf(buffer, "J%4d", (int *) &jmode);
  946.  
  947.     /*  X11_linewidth(width) - set line width */
  948.     else if (*buffer == 'W')
  949.         sscanf(buffer + 1, "%4d", &user_width);
  950.  
  951.     /*   X11_linetype(type) - set line type  */
  952.     else if (*buffer == 'L') {
  953.         sscanf(buffer, "L%4d", <);
  954.         lt = (lt % 8) + 2;
  955.         /* default width is 0 {which X treats as 1} */
  956.         width = widths[lt] ? user_width * widths[lt] : user_width;
  957.         if (dashes[lt][0]) {
  958.         type = LineOnOffDash;
  959.         XSetDashes(dpy, gc, 0, dashes[lt], strlen(dashes[lt]));
  960.         } else {
  961.         type = LineSolid;
  962.         }
  963.         XSetForeground(dpy, gc, colors[lt + 3]);
  964.         XSetLineAttributes(dpy, gc, width, type, CapButt, JoinBevel);
  965.     }
  966.     /*   X11_point(number) - draw a point */
  967.     else if (*buffer == 'P') {
  968.         /* linux sscanf does not like %1d%4d%4d" with Oxxxxyyyy */
  969.         /* sscanf(buffer, "P%1d%4d%4d", &point, &x, &y); */
  970.         point = buffer[1] - '0';
  971.         sscanf(buffer + 2, "%4d%4d", &x, &y);
  972.         if (point == 7) {
  973.         /* set point size */
  974.         px = (int) (x * xscale * pointsize);
  975.         py = (int) (y * yscale * pointsize);
  976.         } else {
  977.         if (type != LineSolid || width != 0) {    /* select solid line */
  978.             XSetLineAttributes(dpy, gc, 0, LineSolid, CapButt, JoinBevel);
  979.         }
  980.         switch (point) {
  981.         case 0:    /* dot */
  982.             XDrawPoint(dpy, plot->pixmap, gc, X(x), Y(y));
  983.             break;
  984.         case 1:    /* do diamond */
  985.             Diamond[0].x = (short) X(x) - px;
  986.             Diamond[0].y = (short) Y(y);
  987.             Diamond[1].x = (short) px;
  988.             Diamond[1].y = (short) -py;
  989.             Diamond[2].x = (short) px;
  990.             Diamond[2].y = (short) py;
  991.             Diamond[3].x = (short) -px;
  992.             Diamond[3].y = (short) py;
  993.             Diamond[4].x = (short) -px;
  994.             Diamond[4].y = (short) -py;
  995.  
  996.             /*
  997.              * Should really do a check with XMaxRequestSize()
  998.              */
  999.             XDrawLines(dpy, plot->pixmap, gc, Diamond, 5, CoordModePrevious);
  1000.             XDrawPoint(dpy, plot->pixmap, gc, X(x), Y(y));
  1001.             break;
  1002.         case 2:    /* do plus */
  1003.             Plus[0].x1 = (short) X(x) - px;
  1004.             Plus[0].y1 = (short) Y(y);
  1005.             Plus[0].x2 = (short) X(x) + px;
  1006.             Plus[0].y2 = (short) Y(y);
  1007.             Plus[1].x1 = (short) X(x);
  1008.             Plus[1].y1 = (short) Y(y) - py;
  1009.             Plus[1].x2 = (short) X(x);
  1010.             Plus[1].y2 = (short) Y(y) + py;
  1011.  
  1012.             XDrawSegments(dpy, plot->pixmap, gc, Plus, 2);
  1013.             break;
  1014.         case 3:    /* do box */
  1015.             XDrawRectangle(dpy, plot->pixmap, gc, X(x) - px, Y(y) - py, (px + px), (py + py));
  1016.             XDrawPoint(dpy, plot->pixmap, gc, X(x), Y(y));
  1017.             break;
  1018.         case 4:    /* do X */
  1019.             Cross[0].x1 = (short) X(x) - px;
  1020.             Cross[0].y1 = (short) Y(y) - py;
  1021.             Cross[0].x2 = (short) X(x) + px;
  1022.             Cross[0].y2 = (short) Y(y) + py;
  1023.             Cross[1].x1 = (short) X(x) - px;
  1024.             Cross[1].y1 = (short) Y(y) + py;
  1025.             Cross[1].x2 = (short) X(x) + px;
  1026.             Cross[1].y2 = (short) Y(y) - py;
  1027.  
  1028.             XDrawSegments(dpy, plot->pixmap, gc, Cross, 2);
  1029.             break;
  1030.         case 5:    /* do triangle */
  1031.             {
  1032.             short temp_x, temp_y;
  1033.  
  1034.             temp_x = (short) (1.33 * (double) px + 0.5);
  1035.             temp_y = (short) (1.33 * (double) py + 0.5);
  1036.  
  1037.             Triangle[0].x = (short) X(x);
  1038.             Triangle[0].y = (short) Y(y) - temp_y;
  1039.             Triangle[1].x = (short) temp_x;
  1040.             Triangle[1].y = (short) 2 *py;
  1041.             Triangle[2].x = (short) -(2 * temp_x);
  1042.             Triangle[2].y = (short) 0;
  1043.             Triangle[3].x = (short) temp_x;
  1044.             Triangle[3].y = (short) -(2 * py);
  1045.  
  1046.             XDrawLines(dpy, plot->pixmap, gc, Triangle, 4, CoordModePrevious);
  1047.             XDrawPoint(dpy, plot->pixmap, gc, X(x), Y(y));
  1048.             }
  1049.             break;
  1050.         case 6:    /* do star */
  1051.             Star[0].x1 = (short) X(x) - px;
  1052.             Star[0].y1 = (short) Y(y);
  1053.             Star[0].x2 = (short) X(x) + px;
  1054.             Star[0].y2 = (short) Y(y);
  1055.             Star[1].x1 = (short) X(x);
  1056.             Star[1].y1 = (short) Y(y) - py;
  1057.             Star[1].x2 = (short) X(x);
  1058.             Star[1].y2 = (short) Y(y) + py;
  1059.             Star[2].x1 = (short) X(x) - px;
  1060.             Star[2].y1 = (short) Y(y) - py;
  1061.             Star[2].x2 = (short) X(x) + px;
  1062.             Star[2].y2 = (short) Y(y) + py;
  1063.             Star[3].x1 = (short) X(x) - px;
  1064.             Star[3].y1 = (short) Y(y) + py;
  1065.             Star[3].x2 = (short) X(x) + px;
  1066.             Star[3].y2 = (short) Y(y) - py;
  1067.  
  1068.             XDrawSegments(dpy, plot->pixmap, gc, Star, 4);
  1069.             break;
  1070.         }
  1071.         if (type != LineSolid || width != 0) {    /* select solid line */
  1072.             XSetLineAttributes(dpy, gc, width, type, CapButt, JoinBevel);
  1073.         }
  1074.         }
  1075.     }
  1076.     }
  1077.  
  1078.     /* set new pixmap as window background */
  1079.     XSetWindowBackgroundPixmap(dpy, plot->window, plot->pixmap);
  1080.  
  1081.     /* trigger exposure of background pixmap */
  1082.     XClearWindow(dpy, plot->window);
  1083.  
  1084. #ifdef EXPORT_SELECTION
  1085.     export_graph(plot);
  1086. #endif
  1087.  
  1088.     XFlush(dpy);
  1089. }
  1090.  
  1091. /*---------------------------------------------------------------------------
  1092.  *  reset all cursors (since we dont have a record of the previous terminal #)
  1093.  *---------------------------------------------------------------------------*/
  1094.  
  1095. void
  1096. reset_cursor()
  1097. {
  1098.     int plot_number;
  1099.     plot_struct *plot = plot_array;
  1100.  
  1101.     for (plot_number = 0, plot = plot_array;
  1102.      plot_number < MAX_WINDOWS;
  1103.      ++plot_number, ++plot) {
  1104.     if (plot->window) {
  1105.         FPRINTF((stderr, "Window for plot %d exists\n", plot_number));
  1106.         XUndefineCursor(dpy, plot->window);;
  1107.     }
  1108.     }
  1109.  
  1110.     FPRINTF((stderr, "Cursors reset\n"));
  1111.     return;
  1112. }
  1113.  
  1114. /*-----------------------------------------------------------------------------
  1115.  *   resize - rescale last plot if window resized
  1116.  *---------------------------------------------------------------------------*/
  1117.  
  1118. plot_struct *
  1119. find_plot(window)
  1120. Window window;
  1121. {
  1122.     int plot_number;
  1123.     plot_struct *plot = plot_array;
  1124.  
  1125.     for (plot_number = 0, plot = plot_array;
  1126.      plot_number < MAX_WINDOWS;
  1127.      ++plot_number, ++plot) {
  1128.     if (plot->window == window) {
  1129.         FPRINTF((stderr, "Event for plot %d\n", plot_number));
  1130.         return plot;
  1131.     }
  1132.     }
  1133.  
  1134.     FPRINTF((stderr, "Bogus window 0x%x in event !\n", window));
  1135.     return NULL;
  1136. }
  1137.  
  1138. void
  1139. process_event(event)
  1140. XEvent *event;
  1141. {
  1142.     FPRINTF((stderr, "Event 0x%x\n", event->type));
  1143.  
  1144.     switch (event->type) {
  1145.     case ConfigureNotify:
  1146.     {
  1147.         plot_struct *plot = find_plot(event->xconfigure.window);
  1148.         if (plot) {
  1149.         int w = event->xconfigure.width, h = event->xconfigure.height;
  1150.  
  1151.         /* store settings in case window is closed then recreated */
  1152.         plot->x = event->xconfigure.x;
  1153.         plot->y = event->xconfigure.y;
  1154.         plot->posn_flags = (plot->posn_flags & ~PPosition) | USPosition;
  1155.  
  1156.         if (w > 1 && h > 1 && (w != plot->width || h != plot->height)) {
  1157.             plot->width = w;
  1158.             plot->height = h;
  1159.             plot->posn_flags = (plot->posn_flags & ~PSize) | USSize;
  1160.             if (plot->pixmap) {
  1161.             /* it is the wrong size now */
  1162.             FPRINTF((stderr, "Free pixmap %d\n", 0));
  1163.             XFreePixmap(dpy, plot->pixmap);
  1164.             plot->pixmap = None;
  1165.             }
  1166.             display(plot);
  1167.         }
  1168.         }
  1169.         break;
  1170.     }
  1171.     case KeyPress:
  1172.     if (event->xkey.keycode == q_keycode) {
  1173.         plot_struct *plot = find_plot(event->xkey.win}Ò}Ó}Ô}Õ}Ö}×}Ø}Ùlot)
  1174.         delete_plot(plot);
  1175.     }
  1176.     break;
  1177.     case ClientMessage:
  1178.     if (event->xclient.message_type == WM_PROTOCOLS &&
  1179.         event->xclient.format == 32 &&
  1180.         event->xclient.data.l[0] == WM_DELETE_WINDOW) {
  1181.         plot_struct *plot = find_plot(event->xclient.window);
  1182.         if (plot)
  1183.         delete_plot(plot);
  1184.     }
  1185.     break;
  1186. #ifdef EXPORT_SELECTION
  1187.     case SelectionNotify:
  1188.     case SelectionRequest:
  1189.     handle_selection_event(event);
  1190.     break;
  1191. #endif
  1192.     }
  1193. }
  1194.  
  1195. /*-----------------------------------------------------------------------------
  1196.  *   preset - determine options, open display, create window
  1197.  *---------------------------------------------------------------------------*/
  1198. /*
  1199. #define On(v) ( !strcmp(v,"on") || !strcmp(v,"true") || \
  1200.                 !strcmp(v,"On") || !strcmp(v,"True") || \
  1201.                 !strcmp(v,"ON") || !strcmp(v,"TRUE") )
  1202. */
  1203. #define On(v) ( !strnicmp(v,"on",2) || !strnicmp(v,"true",4) )
  1204.  
  1205. #define AppDefDir "/usr/lib/X11/app-defaults"
  1206. #ifndef MAXHOSTNAMELEN
  1207. #define MAXHOSTNAMELEN 64
  1208. #endif
  1209.  
  1210. static XrmDatabase dbCmd, dbApp, dbDef, dbEnv, db = (XrmDatabase) 0;
  1211.  
  1212. char *pr_GetR(), *getenv(), *type[20];
  1213. XrmValue value;
  1214.  
  1215. static XrmOptionDescRec options[] = {
  1216.     {"-mono", ".mono", XrmoptionNoArg, (caddr_t) "on"},
  1217.     {"-gray", ".gray", XrmoptionNoArg, (caddr_t) "on"},
  1218.     {"-clear", ".clear", XrmoptionNoArg, (caddr_t) "on"},
  1219.     {"-tvtwm", ".tvtwm", XrmoptionNoArg, (caddr_t) "on"},
  1220.     {"-pointsize", ".pointsize", XrmoptionSepArg, (caddr_t) NULL},
  1221.     {"-display", ".display", XrmoptionSepArg, (caddr_t) NULL},
  1222.     {"-name", ".name", XrmoptionSepArg, (caddr_t) NULL},
  1223.     {"-geometry", "*geometry", XrmoptionSepArg, (caddr_t) NULL},
  1224.     {"-background", "*background", XrmoptionSepArg, (caddr_t) NULL},
  1225.     {"-bg", "*background", XrmoptionSepArg, (caddr_t) NULL},
  1226.     {"-foreground", "*foreground", XrmoptionSepArg, (caddr_t) NULL},
  1227.     {"-fg", "*foreground", XrmoptionSepArg, (caddr_t) NULL},
  1228.     {"-bordercolor", "*bordercolor", XrmoptionSepArg, (caddr_t) NULL},
  1229.     {"-bd", "*bordercolor", XrmoptionSepArg, (caddr_t) NULL},
  1230.     {"-borderwidth", ".borderwidth", XrmoptionSepArg, (caddr_t) NULL},
  1231.     {"-bw", ".borderwidth", XrmoptionSepArg, (caddr_t) NULL},
  1232.     {"-font", "*font", XrmoptionSepArg, (caddr_t) NULL},
  1233.     {"-fn", "*font", XrmoptionSepArg, (caddr_t) NULL},
  1234.     {"-reverse", "*reverseVideo", XrmoptionNoArg, (caddr_t) "on"},
  1235.     {"-rv", "*reverseVideo", XrmoptionNoArg, (caddr_t) "on"},
  1236.     {"+rv", "*reverseVideo", XrmoptionNoArg, (caddr_t) "off"},
  1237.     {"-iconic", "*iconic", XrmoptionNoArg, (caddr_t) "on"},
  1238.     {"-synchronous", "*synchronous", XrmoptionNoArg, (caddr_t) "on"},
  1239.     {"-xnllanguage", "*xnllanguage", XrmoptionSepArg, (caddr_t) NULL},
  1240.     {"-selectionTimeout", "*selectionTimeout", XrmoptionSepArg, (caddr_t) NULL},
  1241.     {"-title", ".title", XrmoptionSepArg, (caddr_t) NULL},
  1242.     {"-xrm", NULL, XrmoptionResArg, (caddr_t) NULL},
  1243.     {"-raise", "*raise", XrmoptionNoArg, (caddr_t) "on"},
  1244.     {"-noraise", "*raise", XrmoptionNoArg, (caddr_t) "off"},
  1245.     {"-persist", "*persist", XrmoptionNoArg, (caddr_t) "on"}
  1246. };
  1247.  
  1248. #define Nopt (sizeof(options) / sizeof(options[0]))
  1249.  
  1250. void
  1251. preset(argc, argv)
  1252. int argc;
  1253. char *argv[];
  1254. {
  1255.     int Argc = argc;
  1256.     char **Argv = argv;
  1257.  
  1258. #ifdef VMS
  1259.     char *ldisplay = (char *) 0;
  1260. #else
  1261.     char *ldisplay = getenv("DISPLAY");
  1262. #endif
  1263.     char *home = getenv("HOME");
  1264.     char *server_defaults, *env, buffer[256];
  1265.  
  1266.     /* avoid bus error when env vars are not set */
  1267.     if (ldisplay == NULL)
  1268.     ldisplay = "";
  1269.     if (home == NULL)
  1270.     home = "";
  1271.  
  1272. /*---set to ignore ^C and ^Z----------------------------------------------*/
  1273.  
  1274.     signal(SIGINT, SIG_IGN);
  1275. #ifdef SIGTSTP
  1276.     signal(SIGTSTP, SIG_IGN);
  1277. #endif
  1278.  
  1279. /*---prescan arguments for "-name"----------------------------------------*/
  1280.  
  1281.     while (++Argv, --Argc > 0) {
  1282.     if (!strcmp(*Argv, "-name") && Argc > 1) {
  1283.         strncpy(Name, Argv[1], sizeof(Name) - 1);
  1284.         strncpy(Class, Argv[1], sizeof(Class) - 1);
  1285.         /* just in case */
  1286.         Name[sizeof(Name)-1] = NUL;
  1287.         Class[sizeof(Class)-1] = NUL;
  1288.         if (Class[0] >= 'a' && Class[0] <= 'z')
  1289.         Class[0] -= 0x20;
  1290.     }
  1291.     }
  1292.     Argc = argc;
  1293.     Argv = argv;
  1294.  
  1295. /*---parse command line---------------------------------------------------*/
  1296.  
  1297.     XrmInitialize();
  1298.     XrmParseCommand(&dbCmd, options, Nopt, Name, &Argc, Argv);
  1299.     if (Argc > 1) {
  1300.     fprintf(stderr, "\n\
  1301. gnuplot: bad option: %s\n\
  1302. gnuplot: X11 aborted.\n", Argv[1]);
  1303.     EXIT(1);
  1304.     }
  1305.     if (pr_GetR(dbCmd, ".display"))
  1306.     ldisplay = (char *) value.addr;
  1307.  
  1308. /*---open display---------------------------------------------------------*/
  1309.  
  1310.     dpy = XOpenDisplay(ldisplay);
  1311.     if (!dpy) {
  1312.     fprintf(stderr, "\n\
  1313. gnuplot: unable to open display '%s'\n\
  1314. gnuplot: X11 aborted.\n", ldisplay);
  1315.     EXIT(1);
  1316.     }
  1317.     scr = DefaultScreen(dpy);
  1318.     vis = DefaultVisual(dpy, scr);
  1319.     D = DefaultDepth(dpy, scr);
  1320.     root = DefaultRootWindow(dpy);
  1321.     server_defaults = XResourceManagerString(dpy);
  1322.  
  1323. /*---get symcode for key q ---*/
  1324.  
  1325.     q_keycode = XKeysymToKeycode(dpy, XK_q);
  1326.  
  1327. /**** atoms we will need later ****/
  1328.  
  1329.     WM_PROTOCOLS = XInternAtom(dpy, "WM_PROTOCOLS", False);
  1330.     WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  1331.  
  1332.  
  1333. /*---get application defaults--(subset of Xt processing)------------------*/
  1334.  
  1335. #ifdef VMS
  1336.     strcpy(buffer, "DECW$USER_DEFAULTS:GNUPLOT_X11.INI");
  1337. #elif defined OS2
  1338. /* for Xfree86 ... */
  1339.     {
  1340.     char *appdefdir = "XFree86/lib/X11/app-defaults";
  1341.     char *xroot = getenv("X11ROOT");
  1342.     sprintf(buffer, "%s/%s/%s", xroot, appdefdir, "Gnuplot");
  1343.     }
  1344. # else /* !OS/2 */
  1345.     strcpy(buffer, AppDefDir);
  1346.     strcat(buffer, "/");
  1347.     strcat(buffer, "Gnuplot");
  1348. #endif /* !VMS */
  1349.  
  1350.     dbApp = XrmGetFileDatabase(buffer);
  1351.     XrmMergeDatabases(dbApp, &db);
  1352.  
  1353. /*---get server or ~/.Xdefaults-------------------------------------------*/
  1354.  
  1355.     if (server_defaults)
  1356.     dbDef = XrmGetStringDatabase(server_defaults);
  1357.     else {
  1358. #ifdef VMS
  1359.     strcpy(buffer, "DECW$USER_DEFAULTS:DECW$XDEFAULTS.DAT");
  1360. #else
  1361.     strcpy(buffer, home);
  1362.     strcat(buffer, ".Xdefaults");
  1363. #endif
  1364.     dbDef = XrmGetFileDatabase(buffer);
  1365.     }
  1366.     XrmMergeDatabases(dbDef, &db);
  1367.  
  1368. /*---get XENVIRONMENT or  ~/.Xdefaults-hostname---------------------------*/
  1369.  
  1370. #ifndef VMS
  1371.     if ((env = getenv("XENVIRONMENT")) != NULL)
  1372.     dbEnv = XrmGetFileDatabase(env);
  1373.     else {
  1374.     char *p = NULL, host[MAXHOSTNAMELEN];
  1375.  
  1376.     if (GP_SYSTEMINFO(host) < 0) {
  1377.         fprintf(stderr, "gnuplot: %s failed. X11 aborted.\n", SYSINFO_METHOD);
  1378.         EXIT(1);
  1379.     }
  1380.     if ((p = strchr(host, '.')) != NULL)
  1381.         *p = '\0';
  1382.     strcpy(buffer, home);
  1383.     strcat(buffer, "/.Xdefaults-");
  1384.     strcat(buffer, host);
  1385.     dbEnv = XrmGetFileDatabase(buffer);
  1386.     }
  1387.     XrmMergeDatabases(dbEnv, &db);
  1388. #endif /* not VMS */
  1389.  
  1390. /*---merge command line options-------------------------------------------*/
  1391.  
  1392.     XrmMergeDatabases(dbCmd, &db);
  1393.  
  1394. /*---set geometry, font, colors, line widths, dash styles, point size-----*/
  1395.  
  1396.     pr_geometry();
  1397.     pr_font();
  1398.     pr_color();
  1399.     pr_width();
  1400.     pr_dashes();
  1401.     pr_pointsize();
  1402.     pr_raise();
  1403.     pr_persist();
  1404. }
  1405.  
  1406. /*-----------------------------------------------------------------------------
  1407.  *   pr_GetR - get resource from database using "-name" option (if any)
  1408.  *---------------------------------------------------------------------------*/
  1409.  
  1410. char *
  1411. pr_GetR(xrdb, resource)
  1412. XrmDatabase xrdb;
  1413. char *resource;
  1414. {
  1415.     char name[128], class[128], *rc;
  1416.  
  1417.     strcpy(name, Name);
  1418.     strcat(name, resource);
  1419.     strcpy(class, Class);
  1420.     strcat(class, resource);
  1421.     rc = XrmGetResource(xrdb, name, class, type, &value)
  1422.     ? (char *) value.addr
  1423.     : (char *) 0;
  1424.     return (rc);
  1425. }
  1426.  
  1427. /*-----------------------------------------------------------------------------
  1428.  *   pr_color - determine color values
  1429.  *---------------------------------------------------------------------------*/
  1430.  
  1431. char color_keys[Ncolors][30] = {
  1432.     "background", "bordercolor", "text", "border", "axis",
  1433.     "line1", "line2", "line3", "line4",
  1434.     "line5", "line6", "line7", "line8"
  1435. };
  1436. char color_values[Ncolors][30] = {
  1437.     "white", "black", "black", "black", "black",
  1438.     "red", "green", "blue", "magenta",
  1439.     "cyan", "sienna", "orange", "coral"
  1440. };
  1441. char gray_values[Ncolors][30] = {
  1442.     "black", "white", "white", "gray50", "gray50",
  1443.     "gray100", "gray60", "gray80", "gray40",
  1444.     "gray90", "gray50", "gray70", "gray30"
  1445. };
  1446.  
  1447. void
  1448. pr_color()
  1449. {
  1450.     unsigned long black = BlackPixel(dpy, scr), white = WhitePixel(dpy, scr);
  1451.     char option[20], color[30], *v, *ctype;
  1452.     XColor xcolor;
  1453.     Colormap cmap;
  1454.     double intensity = -1;
  1455.     int n;
  1456.  
  1457.     pr_GetR(db, ".mono") && On(value.addr) && Mono++;
  1458.     pr_GetR(db, ".gray") && On(value.addr) && Gray++;
  1459.     pr_GetR(db, ".reverseVideo") && On(value.addr) && Rv++;
  1460.  
  1461.     if (!Gray && (vis->class == GrayScale || vis->class == StaticGray))
  1462.     Mono++;
  1463.  
  1464.     if (!Mono) {
  1465.     cmap = DefaultColormap(dpy, scr);
  1466.     ctype = (Gray) ? "Gray" : "Color";
  1467.  
  1468.     for (n = 0; n < Ncolors; n++) {
  1469.         strcpy(option, ".");
  1470.         strcat(option, color_keys[n]);
  1471.         (n > 1) && strcat(option, ctype);
  1472.         v = pr_GetR(db, option)
  1473.         ? (char *) value.addr
  1474.         : ((Gray) ? gray_values[n] : color_values[n]);
  1475.  
  1476.         if (sscanf(v, "%30[^,],%lf", color, &intensity) == 2) {
  1477.         if (intensity < 0 || intensity > 1) {
  1478.             fprintf(stderr, "\ngnuplot: invalid color intensity in '%s'\n",
  1479.                 color);
  1480.             intensity = 1;
  1481.         }
  1482.         } else {
  1483.         strcpy(color, v);
  1484.         intensity = 1;
  1485.         }
  1486.  
  1487.         if (!XParseColor(dpy, cmap, color, &xcolor)) {
  1488.         fprintf(stderr, "\ngnuplot: unable to parse '%s'. Using black.\n",
  1489.             color);
  1490.         colors[n] = black;
  1491.         } else {
  1492.         xcolor.red *= intensity;
  1493.         xcolor.green *= intensity;
  1494.         xcolor.blue *= intensity;
  1495.         if (XAllocColor(dpy, cmap, &xcolor)) {
  1496.             colors[n] = xcolor.pixel;
  1497.         } else {
  1498.             fprintf(stderr, "\ngnuplot: can't allocate '%s'. Using black.\n",
  1499.                 v);
  1500.             colors[n] = black;
  1501.         }
  1502.         }
  1503.     }
  1504.     } else {
  1505.     colors[0] = (Rv) ? black : white;
  1506.     for (n = 1; n < Ncolors; n++)
  1507.         colors[n] = (Rv) ? white : black;
  1508.     }
  1509. }
  1510.  
  1511. /*-----------------------------------------------------------------------------
  1512.  *   pr_dashes - determine line dash styles 
  1513.  *---------------------------------------------------------------------------*/
  1514.  
  1515. char dash_keys[Ndashes][10] = {
  1516.     "border", "axis",
  1517.     "line1", "line2", "line3", "line4", "line5", "line6", "line7", "line8"
  1518. };
  1519.  
  1520. char dash_mono[Ndashes][10] = {
  1521.     "0", "16",
  1522.     "0", "42", "13", "44", "15", "4441", "42", "13"
  1523. };
  1524.  
  1525. char dash_color[Ndashes][10] = {
  1526.     "0", "16",
  1527.     "0", "0", "0", "0", "0", "0", "0", "0"
  1528. };
  1529.  
  1530. void
  1531. pr_dashes()
  1532. {
  1533.     int n, j, l, ok;
  1534.     char option[20], *v;
  1535.  
  1536.     for (n = 0; n < Ndashes; n++) {
  1537.     strcpy(option, ".");
  1538.     strcat(option, dash_keys[n]);
  1539.     strcat(option, "Dashes");
  1540.     v = pr_GetR(db, option)
  1541.         ? (char *) value.addr
  1542.         : ((Mono) ? dash_mono[n] : dash_color[n]);
  1543.     l = strlen(v);
  1544.     if (l == 1 && *v == '0') {
  1545.         dashes[n][0] = (unsigned char) 0;
  1546.         continue;
  1547.     }
  1548.     for (ok = 0, j = 0; j < l; j++) {
  1549.         v[j] >= '1' && v[j] <= '9' && ok++;
  1550.     }
  1551.     if (ok != l || (ok != 2 && ok != 4)) {
  1552.         fprintf(stderr, "gnuplot: illegal dashes value %s:%s\n", option, v);
  1553.         dashes[n][0] = (unsigned char) 0;
  1554.         continue;
  1555.     }
  1556.     for (j = 0; j < l; j++) {
  1557.         dashes[n][j] = (unsigned char) (v[j] - '0');
  1558.     }
  1559.     dashes[n][l] = (unsigned char) 0;
  1560.     }
  1561. }
  1562.  
  1563. /*-----------------------------------------------------------------------------
  1564.  *   pr_font - determine font          
  1565.  *---------------------------------------------------------------------------*/
  1566.  
  1567. void
  1568. pr_font()
  1569. {
  1570.     char *fontname = pr_GetR(db, ".font");
  1571.  
  1572.     if (!fontname)
  1573.     fontname = FallbackFont;
  1574.     font = XLoadQueryFont(dpy, fontname);
  1575.     if (!font) {
  1576.     fprintf(stderr, "\ngnuplot: can't load font '%s'\n", fontname);
  1577.     fprintf(stderr, "gnuplot: using font '%s' instead.\n", FallbackFont);
  1578.     font = XLoadQueryFont(dpy, FallbackFont);
  1579.     if (!font) {
  1580.         fprintf(stderr, "\
  1581. gnuplot: can't load font '%s'\n\
  1582. gnuplot: no useable font - X11 aborted.\n", FallbackFont);
  1583.         EXIT(1);
  1584.     }
  1585.     }
  1586.     vchar = font->ascent + font->descent;
  1587. }
  1588.  
  1589. /*-----------------------------------------------------------------------------
  1590.  *   pr_geometry - determine window geometry      
  1591.  *---------------------------------------------------------------------------*/
  1592.  
  1593. void
  1594. pr_geometry()
  1595. {
  1596.     char *geometry = pr_GetR(db, ".geometry");
  1597.     int x, y, flags;
  1598.     unsigned int w, h;
  1599.  
  1600.     if (geometry) {
  1601.     flags = XParseGeometry(geometry, &x, &y, &w, &h);
  1602.     if (flags & WidthValue)
  1603.         gW = w;
  1604.     if (flags & HeightValue)
  1605.         gH = h;
  1606.     if (flags & (WidthValue | HeightValue))
  1607.         gFlags = (gFlags & ~PSize) | USSize;
  1608.  
  1609.     if (flags & XValue)
  1610.         gX = (flags & XNegative) ? x + DisplayWidth(dpy, scr) - gW - BorderWidth * 2 : x;
  1611.  
  1612.     if (flags & YValue)
  1613.         gY = (flags & YNegative) ? y + DisplayHeight(dpy, scr) - gH - BorderWidth * 2 : y;
  1614.  
  1615.     if (flags & (XValue | YValue))
  1616.         gFlags = (gFlags & ~PPosition) | USPosition;
  1617.     }
  1618. }
  1619.  
  1620. /*-----------------------------------------------------------------------------
  1621.  *   pr_pointsize - determine size of points for 'points' plotting style
  1622.  *---------------------------------------------------------------------------*/
  1623.  
  1624. void
  1625. pr_pointsize()
  1626. {
  1627.     if (pr_GetR(db, ".pointsize")) {
  1628.     if (sscanf((char *) value.addr, "%lf", &pointsize) == 1) {
  1629.         if (pointsize <= 0 || pointsize > 10) {
  1630.         fprintf(stderr, "\ngnuplot: invalid pointsize '%s'\n", value.addr);
  1631.         pointsize = 1;
  1632.         }
  1633.     } else {
  1634.         fprintf(stderr, "\ngnuplot: invalid pointsize '%s'\n", value.addr);
  1635.         pointsize = 1;
  1636.     }
  1637.     } else {
  1638.     pointsize = 1;
  1639.     }
  1640. }
  1641.  
  1642. /*-----------------------------------------------------------------------------
  1643.  *   pr_width - determine line width values
  1644.  *---------------------------------------------------------------------------*/
  1645.  
  1646. char width_keys[Nwidths][30] = {
  1647.     "border", "axis",
  1648.     "line1", "line2", "line3", "line4", "line5", "line6", "line7", "line8"
  1649. };
  1650.  
  1651. void
  1652. pr_width()
  1653. {
  1654.     int n;
  1655.     char option[20], *v;
  1656.  
  1657.     for (n = 0; n < Nwidths; n++) {
  1658.     strcpy(option, ".");
  1659.     strcat(option, width_keys[n]);
  1660.     strcat(option, "Width");
  1661.     if ((v = pr_GetR(db, option)) != NULL) {
  1662.         if (*v < '0' || *v > '4' || strlen(v) > 1)
  1663.         fprintf(stderr, "gnuplot: illegal width value %s:%s\n", option, v);
  1664.         else
  1665.         widths[n] = (unsigned int) atoi(v);
  1666.     }
  1667.     }
  1668. }
  1669.  
  1670. /*-----------------------------------------------------------------------------
  1671.  *   pr_window - create window 
  1672.  *---------------------------------------------------------------------------*/
  1673.  
  1674. Window
  1675. pr_window(flags, x, y, width, height)
  1676. unsigned int flags;
  1677. int x, y;
  1678. unsigned int width, height;
  1679. {
  1680.     char *title = pr_GetR(db, ".title");
  1681.     static XSizeHints hints;
  1682.     int Tvtwm = 0;
  1683.  
  1684.     Window win = XCreateSimpleWindow(dpy, root, x, y, width, height, BorderWidth,
  1685.                      colors[1], colors[0]);
  1686.  
  1687.     /* ask ICCCM-compliant window manager to tell us when close window
  1688.      * has been chosen, rather than just killing us
  1689.      */
  1690.  
  1691.     XChangeProperty(dpy, win, WM_PROTOCOLS, XA_ATOM, 32, PropModeReplace,
  1692.             (unsigned char *) &WM_DELETE_WINDOW, 1);
  1693.  
  1694.     pr_GetR(db, ".clear") && On(value.addr) && Clear++;
  1695.     pr_GetR(db, ".tvtwm") && On(value.addr) && Tvtwm++;
  1696.  
  1697.     if (!Tvtwm) {
  1698.     hints.flags = flags;
  1699.     } else {
  1700.     hints.flags = (flags & ~USPosition) | PPosition;    /* ? */
  1701.     }
  1702.     hints.x = gX;
  1703.     hints.y = gY;
  1704.     hints.width = width;
  1705.     hints.height = height;
  1706.  
  1707.     XSetNormalHints(dpy, win, &hints);
  1708.  
  1709.     if (pr_GetR(db, ".iconic") && On(value.addr)) {
  1710.     XWMHints wmh;
  1711.  
  1712.     wmh.flags = StateHint;
  1713.     wmh.initial_state = IconicState;
  1714.     XSetWMHints(dpy, win, &wmh);
  1715.     }
  1716.     XStoreName(dpy, win, ((title) ? title : Class));
  1717.  
  1718.     XSelectInput(dpy, win, KeyPressMask | StructureNotifyMask);
  1719.     XMapWindow(dpy, win);
  1720.  
  1721.     return win;
  1722. }
  1723.  
  1724.  
  1725. /***** pr_raise ***/
  1726. void
  1727. pr_raise()
  1728. {
  1729.     if (pr_GetR(db, ".raise"))
  1730.     do_raise = (On(value.addr));
  1731. }
  1732.  
  1733.  
  1734. void
  1735. pr_persist()
  1736. {
  1737.     if (pr_GetR(db, ".persist"))
  1738.     persist = (On(value.addr));
  1739. }
  1740.  
  1741. /************ code to handle selection export *********************/
  1742.  
  1743. #ifdef EXPORT_SELECTION
  1744.  
  1745. /* bit of a bodge, but ... */
  1746. static struct plot_struct *exported_plot;
  1747.  
  1748. void
  1749. export_graph(plot)
  1750. struct plot_struct *plot;
  1751. {
  1752.     FPRINTF((stderr, "export_graph(0x%x)\n", plot));
  1753.  
  1754.     XSetSelectionOwner(dpy, EXPORT_SELECTION, plot->window, CurrentTime);
  1755.     /* to check we have selection, we would have to do a
  1756.      * GetSelectionOwner(), but if it failed, it failed - no big deal
  1757.      */
  1758.     exported_plot = plot;
  1759. }
  1760.  
  1761. void
  1762. handle_selection_event(event)
  1763. XEvent *event;
  1764. {
  1765.     switch (event->type) {
  1766.     case SelectionRequest:
  1767.     {
  1768.         XEvent reply;
  1769.  
  1770.         static Atom XA_TARGETS = (Atom) 0;
  1771.         if (XA_TARGETS == 0)
  1772.         XA_TARGETS = XInternAtom(dpy, "TARGETS", False);
  1773.  
  1774.         reply.type = SelectionNotify;
  1775.         reply.xselection.send_event = True;
  1776.         reply.xselection.display = event->xselectionrequest.display;
  1777.         reply.xselection.requestor = event->xselectionrequest.requestor;
  1778.         reply.xselection.selection = event->xselectionrequest.selection;
  1779.         reply.xselection.target = event->xselectionrequest.target;
  1780.         reply.xselection.property = event->xselectionrequest.property;
  1781.         reply.xselection.time = event->xselectionrequest.time;
  1782.  
  1783.         FPRINTF((stderr, "selection request\n"));
  1784.  
  1785.         if (reply.xselection.target == XA_TARGETS) {
  1786.         static Atom targets[] = { XA_PIXMAP, XA_COLORMAP };
  1787.  
  1788.         FPRINTF((stderr, "Targets request from %d\n", reply.xselection.requestor));
  1789.  
  1790.         XChangeProperty(dpy, reply.xselection.requestor,
  1791.                 reply.xselection.property, reply.xselection.target, 32, PropModeReplace,
  1792.                 (unsigned char *) targets, 2);
  1793.         } else if (reply.xselection.target == XA_COLORMAP) {
  1794.         Colormap cmap = DefaultColormap(dpy, 0);
  1795.  
  1796.         FPRINTF((stderr, "colormap request from %d\n", reply.xselection.requestor));
  1797.  
  1798.         XChangeProperty(dpy, reply.xselection.requestor,
  1799.                 reply.xselection.property, reply.xselection.target, 32, PropModeReplace,
  1800.                 (unsigned char *) &cmap, 1);
  1801.         } else if (reply.xselection.target == XA_PIXMAP) {
  1802.  
  1803.         FPRINTF((stderr, "pixmap request from %d\n", reply.xselection.requestor));
  1804.  
  1805.         XChangeProperty(dpy, reply.xselection.requestor,
  1806.                 reply.xselection.property, reply.xselection.target, 32, PropModeReplace,
  1807.                 (unsigned char *) &(exported_plot->pixmap), 1);
  1808.         } else {
  1809.         reply.xselection.property = None;
  1810.         }
  1811.  
  1812.         XSendEvent(dpy, reply.xselection.requestor, False, 0L, &reply);
  1813.         /* we never block on XNextEvent(), so must flush manually
  1814.          * (took me *ages* to find this out !)
  1815.          */
  1816.  
  1817.         XFlush(dpy);
  1818.     }
  1819.     break;
  1820.     }
  1821. }
  1822.  
  1823. #endif /* EXPORT_SELECTION */
  1824.